#include "xlcomm/base/sync_log.h"

#include "xlcomm/base/logger.h"
#include "xlcomm/base/process.h"

namespace xlcomm {

SyncLog::SyncLog(const char* basename, int64_t roll_size, bool thread_safe)
    : basename_(basename),
      roll_size_(roll_size),
      thread_safe_(thread_safe),
      written_bytes_(0) {
  XLCOMM_ASSERT(roll_size_ > 0);
  cur_date_ = DateTime::Now();
  cur_filename_ = GetLogFileName(basename_);
  file_.Open(cur_filename_.c_str(), "a");
  written_bytes_ = file_.Length();
}

void SyncLog::Append(const char* msg, size_t len) {
  if (thread_safe_) {
    std::lock_guard<std::mutex> lock(mutex_);
    AppendUnlock(msg, len);
  } else {
    AppendUnlock(msg, len);
  }
}

void SyncLog::AppendUnlock(const char* msg, size_t len) {
  CommTime now = DateTime::Now();
  if (written_bytes_ >= roll_size_ || cur_date_.year != now.year ||
      cur_date_.month != now.month || cur_date_.day != now.day) {
    RollFile();
  }
  if (file_.Write(msg, len, true)) written_bytes_ += len;
}

void SyncLog::RollFile() {
  std::string filename = GetLogFileName(basename_);
  if (strcmp(filename.c_str(), cur_filename_.c_str()) != 0) {
    file_.Close();
    file_.Open(filename.c_str(), "a");
    written_bytes_ = file_.Length();
    cur_filename_ = filename;
  }
}

void SyncLog::Flush() {
  if (thread_safe_) {
    std::lock_guard<std::mutex> lock(mutex_);
    file_.Flush();
  } else {
    file_.Flush();
  }
}

std::string SyncLog::GetLogFileName(const std::string& basename) {
  char filename[256];
  CommTime now = DateTime::Now();
  std::string hostname = Process::GetHostName();
  uint64_t pid = Process::GetProcessId();
  snprintf(filename, sizeof(filename), "%s.%d%02d%02d-%02d%02d%02d.%s.%llu.log",
           basename.c_str(), now.year, now.month, now.day, now.hour, now.minute,
           now.second, hostname.c_str(), static_cast<unsigned long long>(pid));
  return filename;
}

}  // namespace xlcomm